<template>
  <div>
    <Card title="接口查询" :bordered="false" :dis-hover="true">
      <div slot="extra">
        <Button
          size="small"
          type="primary"
          icon="ios-search"
          class="card-extra-item"
          @click="search"
          >查询</Button
        >
        <Button
          size="small"
          type="default"
          icon="ios-refresh"
          class="card-extra-item"
          @click="reset"
          >重置</Button
        >
        <Button
          size="small"
          type="text"
          :icon="showMore ? 'ios-arrow-up' : 'ios-arrow-down'"
          class="card-extra-item"
          @click="showMore = !showMore"
          >{{ showMore ? "收起" : "展开" }}</Button
        >
      </div>
      <Form
        inline
        label-position="right"
        :label-width="100"
        :model="searchParams"
      >
        <Row>
          <Col span="6">
            <FormItem label="所属项目" style="width: 100%">
              <Select
                v-model="searchParams.project"
                filterable
                clearable
                @on-select="changeProjectOption"
                @on-clear="clearProject"
              >
                <Option
                  v-for="item in projects"
                  :value="item.id"
                  :key="item.id"
                  :label="item.name"
                />
              </Select>
            </FormItem>
          </Col>
          <Col span="6">
            <FormItem label="接口名称" style="width: 100%">
              <Input
                clearable
                placeholder="请输入接口名称"
                v-model="searchParams.name"
              />
            </FormItem>
          </Col>
          <Col span="6">
            <FormItem label="请求URL" style="width: 100%">
              <Input
                clearable
                placeholder="请输入请求URL"
                v-model="searchParams.url"
              />
            </FormItem>
          </Col>
          <Col span="6">
            <FormItem label="接口创建人" style="width: 100%">
              <Select
                v-model="searchParams.creator"
                multiple
                filterable
                :max-tag-count="1"
              >
                <Option
                  v-for="(item, index) in users"
                  :value="item.id"
                  :label="item.real_name"
                  :key="index"
                ></Option>
              </Select>
            </FormItem>
          </Col>
        </Row>
        <CollapseTransition>
          <div v-show="showMore">
            <Row>
              <Col span="6">
                <FormItem label="请求方法" style="width: 100%">
                  <Select
                    v-model="searchParams.method"
                    clearable
                    multiple
                    :max-tag-count="2"
                  >
                    <Option value="GET" label="GET" />
                    <Option value="POST" label="POST" />
                    <Option value="PUT" label="PUT" />
                    <Option value="PATCH" label="PATCH" />
                    <Option value="DELETE" label="DELETE" />
                    <Option value="OPTIONS" label="OPTIONS" />
                    <Option value="HEAD" label="HEAD" />
                  </Select>
                </FormItem>
              </Col>
            </Row>
          </div>
        </CollapseTransition>
      </Form>
    </Card>

    <Card title="接口列表" :bordered="false" :dis-hover="true">
      <div slot="extra">
        <Button
          class="card-extra-item"
          size="small"
          type="primary"
          @click="showDrawer = !showDrawer"
          >{{ showDrawer ? "收起创建接口" : "展开创建接口" }}</Button
        >
        <Button
          size="small"
          type="primary"
          class="card-extra-item"
          @click="showCreateApiModal"
          >创建接口</Button
        >
        <Button
          size="small"
          type="primary"
          class="card-extra-item"
          @click="showModuleSelectTreeModal"
          >接口搬家</Button
        >
        <Button
          class="card-extra-item"
          size="small"
          type="primary"
          @click="importApi = true"
          >导入接口</Button
        >
        <Button
          class="card-extra-item"
          size="small"
          type="primary"
          @click="importApiExcel = true"
          >EXCEL导入接口</Button
        >
        <Button
          class="card-extra-item"
          size="small"
          type="error"
          @click="showBatchDeleteApiModal"
          >删除</Button
        >
      </div>
      <Table
        :columns="apiColumns"
        :data="apiData"
        border
        size="small"
        :tooltip-max-width="500"
        @on-selection-change="selectionChange"
      >
        <template slot-scope="{ row }" slot="project|module">
          <Tooltip placement="bottom" transfer :max-width="500">
            <div slot="content" style="white-space: normal">
              项目：{{ row.project.name }}
              <br />
              模块：{{ row.module ? row.module.name : "" }}
            </div>
            {{ row.project.name }}
            <br />
            {{ row.module ? row.module.name : "" }}
          </Tooltip>
        </template>
        <template slot-scope="{ row }" slot="environment">
          <Tooltip
            placement="bottom"
            transfer
            :max-width="500"
            v-if="row.environment"
          >
            <div slot="content" style="white-space: normal">
              {{ row.environment.name }}
              <br />
              {{ row.environment.base_url }}
            </div>
            {{ row.environment.name }}
            <br />
            {{ row.environment.base_url }}
          </Tooltip>
        </template>
        <template slot-scope="{ row }" slot="url">
          <Tooltip placement="bottom" transfer :max-width="500">
            <div slot="content" style="white-space: normal">
              {{
                row.url + (row.request_params ? "?" + row.request_params : "")
              }}
            </div>
            {{ row.url + (row.request_params ? "?" + row.request_params : "") }}
          </Tooltip>
        </template>
        <template slot-scope="{ row }" slot="modifier">{{
          row.modifier.real_name
        }}</template>
        <template slot-scope="{ row }" slot="status">
          <div style="cursor: pointer" @click="goToTestcase(row)">
            <span
              v-if="
                Number(row.status.split(' / ')[0]) ===
                  Number(row.status.split(' / ')[1]) &&
                Number(row.status.split(' / ')[1]) === 0
              "
              style="color: #ed4014; font-weight: bold; font-size: small"
              >{{ row.status }}</span
            >
            <span
              v-else-if="
                Number(row.status.split(' / ')[0]) <
                  Number(row.status.split(' / ')[1]) &&
                Number(row.status.split(' / ')[0]) === 0
              "
              style="color: #ff9900; font-weight: bold; font-size: small"
              >{{ row.status }}</span
            >
            <span
              v-else-if="
                Number(
                  row.status.split(' / ')[0] <
                    Number(row.status.split(' / ')[1]) &&
                    Number(row.status.split(' / ')[0]) > 0
                )
              "
              style="color: #2db7f5; font-weight: bolder; font-size: small"
              >{{ row.status }}</span
            >
            <span
              v-else-if="
                Number(row.status.split(' / ')[0]) ===
                  Number(row.status.split(' / ')[1]) &&
                Number(row.status.split(' / ')[1]) > 0
              "
              style="color: #19be6b; font-weight: bold; font-size: small"
              >{{ row.status }}</span
            >
          </div>
        </template>
        <template slot-scope="{ row }" slot="action">
          <Button
            size="small"
            type="text"
            style="color: #2d8cf0"
            @click="showEditApiModal(row)"
            >编辑</Button
          >
          <Button
            size="small"
            type="text"
            style="color: #2d8cf0"
            @click="showCopyApiModal(row)"
            >复制</Button
          >
          <Button
            size="small"
            type="text"
            style="color: #2d8cf0"
            @click="showCreateTestcaseModal(row.id)"
            >创建用例</Button
          >
        </template>
      </Table>
      <Page
        transfer
        :total="page.total"
        :current="page.current"
        :page-size="page.pageSize"
        :page-size-opts="page.pageSizeOpts"
        size="small"
        show-elevator
        show-sizer
        show-total
        prev-text="上一页"
        next-text="下一页"
        style="margin-top: 15px"
        @on-change="change"
        @on-page-size-change="pageSizeChange"
      />
    </Card>

    <ApiCreate
      :createApi.sync="createApi"
      @initApiTable="search"
      :api="originApi"
    ></ApiCreate>
    <ApiEdit
      :editApi.sync="editApi"
      @initApiTable="search"
      :api="api"
    ></ApiEdit>
    <ApiImport :importApi.sync="importApi" @initApiTable="search"></ApiImport>
    <ApiExcelImport
      :importApiExcel.sync="importApiExcel"
      @initApiTable="search"
    ></ApiExcelImport>
    <TestcaseCreate
      :createTestcase.sync="createTestcase"
      :apiId.sync="apiId"
      @initApiTable="search"
    ></TestcaseCreate>
    <Modal
      v-model="deleteApiConfirm"
      title="删除接口"
      width="550"
      :mask-closable="false"
      @on-cancel="handleDeleteApiConfirmCancel"
    >
      部分接口已存在测试用例，请选择删除方式
      <div slot="footer">
        <Button type="warning" @click="handleDeleteApiConfirmSubmit(false)"
          >只删除不含有用例的接口</Button
        >
        <Button type="error" @click="handleDeleteApiConfirmSubmit(true)"
          >同时删除接口和用例</Button
        >
        <Button type="primary" @click="handleDeleteApiConfirmCancel"
          >取消</Button
        >
      </div>
    </Modal>
    <Drawer
      title="创建接口"
      :scrollable="true"
      :closable="true"
      v-model="showDrawer"
      :mask="false"
      placement="left"
      width="256"
      draggable
    >
      <Select
        v-model="searchParams.project"
        placeholder="请选择项目"
        clearable
        filterable
        prefix="ios-search"
        @on-select="changeProjectOption"
        @on-clear="clearProject"
      >
        <Option
          v-for="item in projects"
          :value="item.id"
          :key="item.id"
          :label="item.name"
          :tag="item.name"
        />
      </Select>
      <Divider />
      <Tree
        :data="moduleTreeData"
        @on-select-change="getSelectedModuleNodes"
        empty-text="请先选择项目"
      ></Tree>
    </Drawer>
    <Modal
      title="请选择接口的家"
      :closable="false"
      :mask-closable="false"
      :width="600"
      v-model="showModuleSelectTree"
      @on-ok="handleMoveApiSubmit"
      @on-cancel="handleMoveApiCancel"
    >
      <div style="height: 230px">
        <SelectTree v-model="targetModule" :treeData="moduleSelectTreeData">
        </SelectTree>
      </div>
    </Modal>
  </div>
</template>

<script>
import { treeToArray } from "@/libs/custom.utils";
import ApiCreate from "@/view/components/HttpAutoTestService/api/api-create";
import ApiEdit from "@/view/components/HttpAutoTestService/api/api-edit";
import ApiImport from "@/view/components/HttpAutoTestService/api/api-import";
import ApiExcelImport from "@/view/components/HttpAutoTestService/api/api-excel-import";
import TestcaseCreate from "@/view/components/HttpAutoTestService/testcase/testcase-create";
import CollapseTransition from "_c/collapse-transition/collapse-transition.js";
import { getProjectNames } from "@/api/HttpAutoTestService/project";
import { getModuleNames } from "@/api/HttpAutoTestService/module";
import {
  getApis,
  batchDeleteApi,
  moveApi,
} from "@/api/HttpAutoTestService/api";
import { getUserNames } from "@/api/HttpAutoTestService/user";
import SelectTree from "_c/select-tree";

export default {
  name: "api",
  components: {
    ApiCreate,
    ApiEdit,
    ApiImport,
    TestcaseCreate,
    CollapseTransition,
    SelectTree,
    ApiExcelImport,
  },
  data() {
    return {
      importApiExcel: false,
      enableMoveApi: false,
      showModuleSelectTree: false,
      showMore: false,
      moduleTreeData: [],
      showDrawer: false,
      createApi: false,
      editApi: false,
      deleteApiConfirm: false,
      importApi: false,
      createTestcase: false,
      searchParams: {
        project: "",
        module: [],
        name: "",
        url: "",
        method: [],
        creator: [],
      },
      api: {
        id: "",
        name: "",
        project: "",
        module: "",
        url: "",
        method: "",
        headers: {},
        request_data_type: "",
        request_params: "",
        request_data: {},
        remark: "",
      },
      originApi: {
        project: "",
        module: "",
        url: "",
        method: "",
        headers: {},
        request_data_type: "",
        request_params: "",
        request_data: {},
        remark: "",
      },
      apiId: "",
      selectedApis: [],
      apiColumns: [
        {
          type: "selection",
          width: 60,
          align: "center",
          fixed: "left",
        },
        {
          title: "接口名称",
          key: "name",
          width: 350,
          tooltip: true,
        },
        {
          title: "项目|模块",
          slot: "project|module",
          width: 350,
          ellipsis: true,
        },
        {
          title: "运行环境",
          slot: "environment",
          width: 250,
          ellipsis: true,
        },
        {
          title: "请求URL",
          slot: "url",
          width: 350,
          ellipsis: true,
        },
        {
          title: "请求方法",
          key: "method",
          align: "center",
          width: 100,
        },
        {
          title: "Headers参数示例",
          key: "headers",
          width: 350,
          ellipsis: true,
        },
        {
          title: "Body参数类型",
          key: "request_data_type",
          align: "center",
          width: 120,
        },
        {
          title: "Body参数示例",
          key: "request_data",
          width: 350,
          ellipsis: true,
        },
        {
          title: "最近维护人",
          slot: "modifier",
          align: "center",
          width: 120,
        },
        {
          title: "接口ID",
          key: "id",
          width: 270,
          tooltip: true,
          align: "center",
        },
        {
          title: "通过/总计",
          slot: "status",
          align: "center",
          width: 90,
          fixed: "right",
        },
        {
          title: "操作",
          slot: "action",
          width: 200,
          align: "center",
          fixed: "right",
        },
      ],
      apiData: [],
      users: [],
      page: {
        current: 1,
        total: 0,
        pageSize: 50,
        pageSizeOpts: [10, 30, 50, 100, 200],
      },
      projects: [],
      moduleSelectTreeData: [],
      targetModule: "",
    };
  },
  mounted() {
    this.searchParams.creator = [this.$store.state.user.id];
    this.search();
    getProjectNames()
      .then((res) => {
        this.projects = res.data;
      })
      .catch((err) => {
        this.$Modal.error({
          title: "系统异常，请联系管理员……",
          content: JSON.stringify(err),
          closable: true,
        });
      });
    // 获取用户
    getUserNames()
      .then((res) => {
        this.users = res.data;
      })
      .catch((err) => {
        this.$Modal.error({
          title: "系统异常，请联系管理员……",
          content: JSON.stringify(err),
          closable: true,
        });
      });
  },
  methods: {
    reset() {
      this.searchParams = {
        project: "",
        module: [],
        name: "",
        url: "",
        method: [],
        creator: [],
      };
      this.moduleTreeData = [];
      this.search();
    },
    search(page) {
      let data = {
        project: this.searchParams.project,
        module: this.searchParams.module.toString(),
        name: this.searchParams.name,
        url: this.searchParams.url,
        method: this.searchParams.method.toString(),
        creator: this.searchParams.creator.toString(),
        page: 1,
        page_size: this.page.pageSize,
      };
      if (typeof page == "number") {
        data.page = page;
      }
      this.page.current = data.page;

      getApis(data)
        .then((res) => {
          this.enableMoveApi = this.searchParams.project ? true : false;
          const data = res.data;
          this.apiData = data.results;
          this.page.total = data.count;
          if (data.next === null) {
            this.page.current = Math.ceil(this.page.total / this.page.pageSize);
          }
          if (data.previous === null) {
            this.page.current = 1;
          }
        })
        .catch((err) => {
          this.$Modal.error({
            title: "系统异常，请联系管理员……",
            content: JSON.stringify(err),
            closable: true,
          });
        });
    },
    showCreateApiModal() {
      this.createApi = true;
    },
    showCopyApiModal(row) {
      let data = {
        project: row.project ? row.project.id : "",
        module: row.module ? row.module.id : "",
        name: row.name,
        url: row.url,
        method: row.method,
        headers: row.headers,
        request_data_type: row.request_data_type,
        request_params: row.request_params,
        request_data: row.request_data,
        remark: row.remark,
        environment: row.environment.id,
      };
      if (data["request_params"]) {
        data["url"] = data["url"] + "?" + data["request_params"];
        data["request_params"] = "";
      }

      this.originApi = data;
      this.createApi = true;
    },
    showEditApiModal(row) {
      let data = {
        id: row.id,
        project: row.project ? row.project.id : "",
        module: row.module ? row.module.id : "",
        name: row.name,
        url: row.url,
        method: row.method,
        headers: row.headers,
        request_data_type: row.request_data_type,
        request_params: row.request_params,
        request_data: row.request_data,
        remark: row.remark,
        environment: row.environment ? row.environment.id : "",
      };
      if (data["request_params"]) {
        data["url"] = data["url"] + "?" + data["request_params"];
        data["request_params"] = "";
      }
      this.api = data;
      this.editApi = true;
    },
    showBatchDeleteApiModal() {
      if (this.selectedApis.length > 0) {
        this.deleteApiConfirm = true;
      } else {
        this.$Message.info("请选择需要删除的接口");
      }
    },
    selectionChange(val) {
      this.selectedApis = val.map((item) => {
        return item.id;
      });
    },
    showCreateTestcaseModal(id) {
      this.apiId = id;
      this.createTestcase = true;
    },
    // 删除API（取消）
    handleDeleteApiConfirmCancel() {
      this.deleteApiConfirm = false;
      this.selectedApis = [];
      this.search();
    },
    // 删除API（确认）
    handleDeleteApiConfirmSubmit(cascade) {
      let data = {
        cascade: cascade,
        apis: this.selectedApis,
      };
      batchDeleteApi(data)
        .then((res) => {
          this.$Message.info("删除成功");
          this.handleDeleteApiConfirmCancel();
        })
        .catch((err) => {
          this.$Modal.error({
            title: "系统异常，请联系管理员……",
            content: JSON.stringify(err),
            closable: true,
          });
        });
    },
    change(val) {
      this.page.current = val;
      this.search(val);
    },
    pageSizeChange(val) {
      this.page.pageSize = val;
      this.search();
    },
    // 跳转到用例列表页
    goToTestcase(val) {
      this.$router.push({
        name: "testcase_testsuite",
        query: { api: val.id, project: val.project.id },
      });
    },
    // 选择模块节点
    getSelectedModuleNodes(val) {
      const result = treeToArray(val);
      this.searchParams.module = result.map((item) => {
        return item.id;
      });
      this.search();
    },
    // 选择所属项目
    changeProjectOption(val) {
      let project = val.value;
      this.searchParams.project = project;
      this.searchParams.module = [];
      this.search();
      this.getModuleNames(project);
    },
    // 清除所属项目
    clearProject() {
      this.searchParams.project = "";
      this.searchParams.module = [];
      this.moduleTreeData = [];
      this.searchParams.module = [];
      this.search();
    },
    // 获取接口所属模块
    getModuleNames(project) {
      getModuleNames({ project: project })
        .then((res) => {
          let moduleNames = res.data;
          // 获取创建接口抽屉中的模块树
          this.getModuleTreeData(moduleNames);
          // 获取接口搬家弹框中的模块树
          this.getModuleSelectTreeData(moduleNames);
        })
        .catch((err) => {
          this.$Modal.error({
            title: "系统异常，请联系管理员……",
            content: JSON.stringify(err),
            closable: true,
          });
        });
    },
    // 获取创建接口抽屉中的模块树
    getModuleTreeData(moduleNames) {
      let data = moduleNames.map((item) => {
        return {
          id: item.id,
          title: item.name,
          parent: item.parent,
          expand: true,
          render: (h, { root, node, data }) => {
            return h(
              "div",
              {
                style: {
                  display: "flex",
                  justifyContent: "space-between",
                  alignItems: "center",
                  width: "100%",
                },
              },
              [
                h(
                  "span",
                  {
                    style: {
                      overflow: "hidden",
                      whiteSpace: "nowrap",
                    },
                  },
                  data.title
                ),
                h(
                  "tooltip",
                  {
                    props: {
                      content: "创建接口",
                      transfer: true,
                    },
                  },
                  [
                    h("Button", {
                      props: {
                        icon: "md-add",
                        type: "text",
                        size: "small",
                      },
                      style: {
                        color: "#2d8cf0",
                      },
                      on: {
                        click: () => {
                          let api = {
                            project: this.searchParams.project,
                            module: data.id,
                            url: "",
                            method: "POST",
                            headers: {
                              "Content-Type": "application/json",
                            },
                            request_data_type: "Json",
                            request_params: "",
                            request_data: {},
                            remark: "",
                          };
                          this.originApi = api;
                          this.createApi = true;
                        },
                      },
                    }),
                  ]
                ),
              ]
            );
          },
        };
      });
      let arrayToTree = require("array-to-tree");
      this.moduleTreeData = arrayToTree(data, {
        parentProperty: "parent",
        childrenProperty: "children",
        customID: "id",
      });
    },
    // 获取接口搬家弹框中的模块树
    getModuleSelectTreeData(moduleNames) {
      let data = moduleNames.map((item) => {
        return {
          value: item.id,
          title: item.name,
          parent: item.parent,
          expand: true,
        };
      });
      let arrayToTree = require("array-to-tree");
      this.moduleSelectTreeData = arrayToTree(data, {
        parentProperty: "parent",
        childrenProperty: "children",
        customID: "value",
      });
    },
    showModuleSelectTreeModal() {
      if (this.selectedApis.length > 0) {
        if (this.enableMoveApi) {
          this.showModuleSelectTree = true;
        } else {
          this.$Message.info(
            "待搬家的接口，必须是【所属项目】查询条件的查询结果"
          );
        }
      } else {
        this.$Message.info("请选择需要搬家的接口");
      }
    },
    handleMoveApiSubmit() {
      let data = {
        module: this.targetModule,
        apis: this.selectedApis,
      };
      moveApi(data).then((res) => {
        if (res.status === 200) {
          this.$Message.info("接口搬家成功");
          this.handleMoveApiCancel();
        } else {
          this.$Message.error("接口搬家失败");
        }
      });
    },
    handleMoveApiCancel() {
      this.showModuleSelectTree = false;
      this.selectedApis = [];
      this.targetModule = "";
      this.search();
    },
  },
};
</script>

<style>
.ivu-tree-title {
  width: 100%;
}
</style>
